package com.woniu113.junk.user.service.impl;

import cn.hutool.core.lang.Snowflake;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.woniu113.junk.commons.util.AliyunOSS;

import com.woniu113.junk.commons.util.RedisUtil;
import com.woniu113.junk.user.Param.userInfo.*;
import com.woniu113.junk.user.dto.SFRZDTO;
import com.woniu113.junk.user.dto.userinfo.FindUserInfoDTO;
import com.woniu113.junk.user.exception.UserException;
import com.woniu113.junk.user.mapper.LogMapper;

import com.woniu113.junk.user.model.Log;
import com.woniu113.junk.user.model.UserInfo;
import com.woniu113.junk.user.mapper.UserInfoMapper;
import com.woniu113.junk.user.service.UserInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniu113.junk.user.util.MD5Util;
import com.woniu113.junk.user.util.RedisKeyUtil;
import com.woniu113.junk.user.util.SFRZUtil;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import java.net.InetAddress;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 蜡笔没了小新
 * @since 2024年10月16日
 */
@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {
    @Resource
    private UserInfoMapper userInfoMapper;
    @Resource
    private LogMapper logMapper;
    @Resource
    private AliyunOSS aliyunOSS;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private RabbitTemplate rabbitTemplate;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private SFRZUtil sfrzUtil;

    @Override
    /*禁用账户*/
    public void disableAccount(Integer userId) {
        UserInfo userInfo = userInfoMapper.selectById(userId);
        if (userInfo==null)throw new UserException("用户不存在",2001);
        if (userInfo.getUserState()!=0)throw new UserException("用户状态异常",2002);
        userInfo.setUserState(1);
        userInfoMapper.updateById(userInfo);
    }

    @Override
    /*启用账户*/
    public void enableAccount(Integer userId) {
        UserInfo userInfo = userInfoMapper.selectById(userId);
        if (userInfo==null)throw new UserException("用户不存在",2001);
        if (userInfo.getUserState()!=1)throw new UserException("用户状态异常",2002);
        userInfo.setUserState(0);
        userInfoMapper.updateById(userInfo);
    }

    @Override
    /*删除账户*/
    public void deleteAccount(Integer userId) {
        UserInfo userInfo = userInfoMapper.selectById(userId);
        if (userInfo==null)throw new UserException("用户不存在",2001);
        if (userInfo.getUserState()==2)throw new UserException("用户状态异常",2002);
        userInfo.setUserState(2);
        userInfoMapper.updateById(userInfo);
    }

    @Override
    /*给用户添加积分*/
    public void addIntegralById(IntegralParam param) {
        /*拿到用户信息进行判断*/
        UserInfo userInfo = userInfoMapper.selectById(param.getUserId());
        if (userInfo==null)throw new UserException("用户不存在",2001);
        if (userInfo.getUserState()!=0)throw new UserException("用户状态异常",2002);
        userInfo.setIntegral(userInfo.getIntegral()+param.getIntegral());
        userInfoMapper.updateById(userInfo);
    }

    @Override
    /*给用户减少积分*/
    public void reduceIntegralById(IntegralParam param) {
        /*拿到用户信息*/
        UserInfo userInfo = userInfoMapper.selectById(param.getUserId());
        if (userInfo==null)throw new UserException("用户不存在",2001);
        if (userInfo.getUserState()!=0)throw new UserException("用户状态异常",2002);
        /*判断积分是否充足*/
        if (userInfo.getIntegral()<param.getIntegral())throw new UserException("积分不足",2003);
        userInfo.setIntegral(userInfo.getIntegral()-param.getIntegral());
        userInfoMapper.updateById(userInfo);
    }

    @Override
    /*添加用户信誉分*/
    public void addScore(ScoreParam param) {
        /*拿到用户信息*/
        UserInfo userInfo = userInfoMapper.selectById(param.getUserId());
        if (userInfo==null)throw new UserException("用户不存在",2001);
        if (userInfo.getUserState()!=0)throw new UserException("用户状态异常",2002);
        if (param.getScore()==100)throw new UserException("信誉分已经满了",2004);
        /*判断是否超过上限*/
        if (param.getScore()+userInfo.getScore()>100){
            userInfo.setScore(100);
        }else{
            userInfo.setScore(userInfo.getScore()+param.getScore());
        }
        userInfoMapper.updateById(userInfo);

    }

    @Override
    /*减少用户信誉分*/
    public void reduceScore(ScoreParam param) {
        /*拿到用户信息*/
        UserInfo userInfo = userInfoMapper.selectById(param.getUserId());
        if (userInfo==null)throw new UserException("用户不存在",2001);
        if (userInfo.getUserState()!=0)throw new UserException("用户状态异常",2002);
        /*判断是否超过下限*/
        /*信誉分低于60禁用账户*/
        if (userInfo.getScore()-param.getScore()<60){
            userInfo.setScore(60);
            userInfo.setUserState(1);
        }else{
            userInfo.setScore(userInfo.getScore()-param.getScore());
        }
        userInfoMapper.updateById(userInfo);
    }

    @Override
    /*验证密码*/
    public void userCheckOldPassword(UserPasswordParam param) throws Exception {
        //1.根据用户id查询用户信息
        UserInfo userInfo = userInfoMapper.selectById(param.getUserId());
        //2.判断用户是否存在
        if (userInfo==null)throw new UserException("用户不存在",2001);
        if (userInfo.getUserState()!=0)throw new UserException("用户状态异常",2002);
        //3.判断密码是否为空
        if (param.getPassword()==null)throw new UserException("密码为空",2005);
        String s = MD5Util.md5(param.getPassword(), userInfo.getUserName());
        //4.判断密码是否正确
        if (!s.equals(userInfo.getPassword()))throw new UserException("密码错误",2006);
    }

    @Override
    /*修改密码*/
    public void userUpdatePassword(UserPasswordParam param) throws Exception {
        //1.根据用户id查询用户信息
        UserInfo userInfo = userInfoMapper.selectById(param.getUserId());
        //2.判断用户是否存在
        if (userInfo==null)throw new UserException("用户不存在",2001);
        if (userInfo.getUserState()!=0)throw new UserException("用户状态异常",2002);
        //3.判断密码是否为空
        if (param.getPassword()==null)throw new UserException("密码为空",2005);
        //4.修改密码
        userInfo.setPassword(MD5Util.md5(param.getPassword(),userInfo.getUserName()));
        userInfoMapper.updateById(userInfo);
    }

    @Override
    /*用户登录*/
    public UserInfo adminLog(UserLogParam param) throws Exception {
        //1.根据用户名查询用户信息
        QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_name",param.getUserName());
        List<UserInfo> userInfos = userInfoMapper.selectList(wrapper);
        //2.判断用户是否存在
        if (userInfos.isEmpty())throw new UserException("用户不存在",2001);
        UserInfo userInfo = userInfos.get(0);
        //3.判断用户状态
        if (userInfo.getUserState()!=0)throw new UserException("用户状态异常",2002);
        //4.判断密码是否正确
        if (!(MD5Util.md5(param.getPassword(),param.getUserName()).equals(userInfo.getPassword())))throw new UserException("密码错误",2006);
        //5.记录登录日志
        //写入登录日志
        Log log = new Log();
        log.setAccountId(userInfo.getUserId());
        log.setLogTime(LocalDateTime.now());
        log.setUserType(0);
        log.setLoginHost(InetAddress.getLocalHost().getHostAddress());
        log.setControls("登录");
        logMapper.insert(log);
        return userInfo;
    }

    @Override
    /*更新用户头像*/
    public void updateUserHeaderImg(UserHeaderImgParam param) throws Exception {
        UserInfo userInfo = userInfoMapper.selectById(param.getUserId());
        if (userInfo==null)throw new UserException("用户不存在",2001);
        if (userInfo.getUserState()!=0)throw new UserException("用户状态异常",2002);
        //处理图片
        //生成文件名称
        String originalFilename = param.getUserHeaderImg().getOriginalFilename();//传入过来的文件的原名字getOriginalFilename
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));//查找最后一个点的位置,并从该点开始截取到末尾(即可生成文件的后缀)
        //生成随机的文件名称（雪花算法）
        Snowflake snowflake = new Snowflake(1, 1);
        String prefix = snowflake.nextIdStr();//通过雪花算法随机生成的前缀
        //文件上传到aliyunoss
        String filePath = aliyunOSS.ProcessPicture(param.getUserHeaderImg());
        userInfo.setHeadImage(filePath);
        userInfoMapper.updateById(userInfo);
    }

    @Override
    /*发送注册验证码*/
    public void sendRegisterCode(String phoneNumber) throws Exception {
        if (redisUtil.exists(RedisKeyUtil.REGISTER_CODE_SENT(phoneNumber))){
            throw new UserException("验证码发送频繁",2007);
        }
        //判断一小时内的发送次数
        if(redisUtil.exists(RedisKeyUtil.SEND_NUMBER(phoneNumber))){
            int number = Integer.parseInt(redisUtil.get(RedisKeyUtil.SEND_NUMBER(phoneNumber)));
            if (number>=5){
                throw new UserException("验证码发送次数过多",2008);
            }

        }
        //验证手机号是否被注册
        QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_phone",phoneNumber).ne("user_state",2);
        List<UserInfo> userInfos1 = userInfoMapper.selectList(wrapper);
        if (!userInfos1.isEmpty()){
            throw new UserException("用户手机号已被注册",2009);
        }
        //将手机号码保存到队列中
        rabbitTemplate.convertAndSend("register_phone_queue",phoneNumber);
    }

    @Override
    /*用户注册*/
    public void addUserInfo(AddUserInfoParam param) throws Exception {
        //判断验证码是否正确
        String code = redisUtil.get(RedisKeyUtil.REGISTER_CODE_kEY(param.getPhoneNumber()));
        if (code==null){
            throw new UserException("请重新发送验证码",2001);
        }
        if (!code.equals(param.getCode())){
            throw new UserException("验证码错误",2002);
        }
        //创建两把锁
        RLock userNameLock = redissonClient.getFairLock(RedisKeyUtil.LOCK_USERNAME(param.getUserName()));
        RLock userPhoneLock = redissonClient.getFairLock(RedisKeyUtil.LOCK_USERPHONE(param.getPhoneNumber()));
        RLock lock = redissonClient.getMultiLock(userNameLock, userPhoneLock);
        boolean getLock = lock.tryLock(10, TimeUnit.SECONDS);//获取锁时会阻塞程序
        try{
            //判断是否获取到锁
            if (getLock){
                //判断用户名是否被注册
                QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
                wrapper.eq("user_name",param.getUserName());
                List<UserInfo> userInfos1 = userInfoMapper.selectList(wrapper);
                if (!userInfos1.isEmpty()){
                    throw new UserException("用户名已存在",2003);
                }
                //判断手机号是否被注册
                wrapper.clear();
                wrapper.eq("user_phone",param.getPhoneNumber());
                List<UserInfo> userInfos2 = userInfoMapper.selectList(wrapper);
                if (!userInfos2.isEmpty()){
                    throw new UserException("用户手机号已被注册",2009);
                }
                //添加用户
                UserInfo userInfo = new UserInfo();
                userInfo.setUserName(param.getUserName());
                userInfo.setPassword(MD5Util.md5(param.getPassword(),param.getUserName()));
                userInfo.setUserPhone(param.getPhoneNumber());
                userInfo.setNickName(param.getUserName());
                userInfo.setUserState(0);
                userInfo.setIntegral(0);
                userInfo.setScore(100);
                userInfo.setNickName(param.getUserName());
                save(userInfo);
                //删除验证码
                redisUtil.delete(RedisKeyUtil.REGISTER_CODE_kEY(param.getPhoneNumber()));

            }else{
                //未获取到锁
                throw new UserException("服务器繁忙，请稍后再试",2010);
            }
        }finally {
            //释放锁
            lock.unlock();
        }
    }

    @Override
    /*发送登录验证码*/
    public void sendLoginCode(String phoneNumber) throws Exception {
        //判断一分钟内是否发送过验证码
        if (redisUtil.exists(RedisKeyUtil.USER_LOGIN_CODE_SENT(phoneNumber))){
            throw new UserException("验证码发送频繁",2007);
        }
        //判断一小时内的发送次数
        if(redisUtil.exists(RedisKeyUtil.SENT_USER_LOGIN_CODE_NUMBER(phoneNumber))){
            int number = Integer.parseInt(redisUtil.get(RedisKeyUtil.SENT_USER_LOGIN_CODE_NUMBER(phoneNumber)));
            if (number>=5){
                throw new UserException("验证码发送次数过多",2008);
            }

        }
        //验证手机号是否被注册
        QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_phone",phoneNumber).ne("user_state",2);
        List<UserInfo> userInfos1 = userInfoMapper.selectList(wrapper);
        if (userInfos1.isEmpty()){
            throw new UserException("用户手机号未注册或状态异常",2011);
        }
        if (userInfos1.get(0).getUserState()==1)throw new UserException("用户状态异常",2002);
        //将手机号码保存到队列中
        rabbitTemplate.convertAndSend("user_login_phone_queue",phoneNumber);
    }

    @Override
    /*用户登录*/
    public UserInfo userCodeLogin(UserCodeLoginParam param) throws Exception {
        //用户在发送验证码时的验证码
        String code = redisUtil.get(RedisKeyUtil.USER_LOGIN_CODE_KEY(param.getUserPhone()));
        //输入的验证码与发送的手机验证码不相同
        if (!param.getCode().equals(code)){
            throw new UserException("验证码不正确",2004);
        }
        //查询用户
        QueryWrapper<UserInfo> queryWrapper =new QueryWrapper<>();
        queryWrapper.eq("user_phone",param.getUserPhone())
                .eq("user_state",0);
        List<UserInfo> userInfos = userInfoMapper.selectList(queryWrapper);
        //未查询到用户
        if (userInfos.isEmpty()){//为空表示手机号未注册或账号失效
            throw new UserException("用户手机号未注册或状态异常",2011);
        }
        UserInfo userInfo = userInfos.get(0);
        Log log = new Log();
        log.setAccountId(userInfo.getUserId());
        log.setLogTime(LocalDateTime.now());
        log.setUserType(0);
        log.setLoginHost(InetAddress.getLocalHost().getHostAddress());
        log.setControls("手机号登录");
        logMapper.insert(log);
        return userInfo;
    }

    @Override
    public void updateUser(UserNikeNameParam param) {
        UserInfo userInfo = userInfoMapper.selectById(param.getUserId());
        if (userInfo==null)throw new UserException("用户不存在",2001);
        if (userInfo.getUserState()!=0)throw new UserException("用户状态异常",2002);
        if (param.getUserNikeName().equals(userInfo.getNickName()))throw new UserException("昵称未修改",2012);
        userInfo.setNickName(param.getUserNikeName());
        userInfoMapper.updateById(userInfo);
    }

    @Override
    public void sendUpCode(String phoneNumber) throws Exception {
        //判断一分钟内是否发送过验证码
        if (redisUtil.exists(RedisKeyUtil.USER_UP_CODE_SENT(phoneNumber))){
            throw new UserException("验证码发送频繁",2007);
        }
        //判断一小时内的发送次数
        if(redisUtil.exists(RedisKeyUtil.SENT_USER_UP_CODE_NUMBER(phoneNumber))){
            int number = Integer.parseInt(redisUtil.get(RedisKeyUtil.SENT_USER_UP_CODE_NUMBER(phoneNumber)));
            if (number>=5){
                throw new UserException("验证码发送次数过多",2008);
            }
        }
        //验证手机号是否被注册
        QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_phone",phoneNumber).ne("user_state",2);
        List<UserInfo> userInfos1 = userInfoMapper.selectList(wrapper);
        if (!userInfos1.isEmpty()){
            throw new UserException("用户手机号已被注册",2009);
        }
        //将手机号码保存到队列中
        rabbitTemplate.convertAndSend("user_up_phone_queue",phoneNumber);
    }

    @Override
    public void upUserPhone(UserUpPhoneParam param) throws Exception {
        //用户在发送验证码时的验证码
        String code = redisUtil.get(RedisKeyUtil.USER_UP_CODE_KEY(param.getUserPhone()));
        //输入的验证码与发送的手机验证码不相同
        if (!param.getCode().equals(code)){
            throw new UserException("验证码不正确",2004);
        }
        UserInfo userInfo = userInfoMapper.selectById(param.getUserId());
        if (userInfo==null)throw new UserException("用户不存在",2001);
        if (userInfo.getUserState()!=0)throw new UserException("用户状态异常",2002);
        userInfo.setUserPhone(param.getUserPhone());
        userInfoMapper.updateById(userInfo);
    }

//    @Override
//    public Page<UserInfo> findAll(UserFdAllParam param) {
//        Page<UserInfo> page =new Page<>(param.getPageNum(), param.getPageSize());
//        List<UserInfo> userInfoList = userInfoMapper.findAll(param.getNikeName(),param.getUserStatus(),param.getMinIntegral(),param.getMaxIntegral(),page);
//        page.setRecords(userInfoList);
//        page.setTotal(userInfoList.size());
//        return page;
//    }

    @Override
    public FindUserInfoDTO findAll(UserFdAllParam param, int offset) {
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        if (param.getNikeName()!=null && !param.getNikeName().equals("")){
            queryWrapper.eq("nick_name",param.getNikeName());
        }
        if (param.getUserStatus()!=null){
            queryWrapper.eq("user_state",param.getUserStatus());
        }
        if (param.getMinIntegral()!=null){
            queryWrapper.gt("integral",param.getMinIntegral());
        }
        if (param.getMaxIntegral()!=null){
            queryWrapper.lt("integral",param.getMaxIntegral());
        }
        int size = Math.toIntExact(userInfoMapper.selectCount(queryWrapper)); // 获取符合条件的总记录数
        queryWrapper.last("LIMIT " + offset + ", " + param.getPageSize());
        List<UserInfo> infos = userInfoMapper.selectList(queryWrapper);
        FindUserInfoDTO dto = new FindUserInfoDTO();
        dto.setList(infos);
        dto.setTotal(size);
        return dto;
    }

    @Override
    public SFRZDTO realNameAuthentication(RealNameAuthenticationParam param) throws Exception {
        //1.判断当前登录用户是否存在以及状态是否正常
        UserInfo userInfo = userInfoMapper.selectById(param.getUserId());
        if (userInfo==null){
            throw new UserException("用户不存在",2001);
        }
        if (userInfo.getUserState()!=0){
            throw new UserException("用户状态异常",2002);
        }
        //2.判断该身份证是否已经被认证过
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("car_id",param.getIdCard()).eq("user_state",0);
        List<UserInfo> userInfos = userInfoMapper.selectList(queryWrapper);
        if (!userInfos.isEmpty()){
            throw new UserException("该身份证已被认证过",2013);
        }
        //3.进行实名认证
        SFRZDTO sfrz = sfrzUtil.sfrz(param.getRealName(), param.getIdCard());
        if (sfrz.getDesc().equals("不一致")){//实名认证不通过
            throw new UserException("实名认证不通过,身份证信息无法对应真实姓名",2014);
        }
        //4.存入数据库中
        userInfo.setRealName(param.getRealName());
        userInfo.setCarId(param.getIdCard());
        userInfo.setSex(sfrz.getSex());
        userInfoMapper.updateById(userInfo);
        return sfrz;
    }

    @Override
    public UserInfo userInfo(int userId) {
        UserInfo userInfo = userInfoMapper.selectById(userId);
        if (userInfo==null)throw new UserException("用户不存在",2001);
        if (userInfo.getUserState()!=0)throw new UserException("用户状态异常",2002);
        return userInfo;
    }




}
